#pragma once

#include <stdint.h>
#include <vector>
#include "base/core/com_define.h"
#include <string.h>
#include <stdlib.h>

class ByteBuffer 
{
private:
	size_t m_rpos;
	size_t m_wpos;
	std::vector<uint8_t> m_storage;

public:
    const static size_t DEFAULT_SIZE = 0x1000;

    ByteBuffer() : m_rpos(0), m_wpos(0) 
	{
        m_storage.reserve(DEFAULT_SIZE); 
    }

    ByteBuffer(size_t size) : m_rpos(0), m_wpos(0) 
	{
        m_storage.reserve(size);
    }

    ByteBuffer(const ByteBuffer& buf) : 
        m_rpos(buf.m_rpos), m_wpos(buf.m_wpos), m_storage(buf.m_storage) 
	{}

    const uint8_t * contents() const { return &m_storage[0]; }

    void clear() 
	{
        m_storage.clear();
        m_rpos = 0, m_wpos = 0;
    }

    template <typename T> void put(size_t pos, T value) 
	{
        put(pos, (uint8_t *)&value, sizeof(value));
    }

    size_t read_pos() const { return m_rpos; }

    void set_read_pos(size_t rpos) { m_rpos = rpos; }

    size_t write_pos() const { return m_wpos; }

    void set_write_pos(size_t wpos) { m_wpos = wpos; }

    template<typename T>
    bool read_skip() { return read_skip(sizeof(T)); }

    bool read_skip(size_t skip) 
	{
        m_rpos += skip;
        return m_rpos <= size();
    }

    template <typename T> 
    bool read(T* t) 
	{
        bool result = read<T>(m_rpos, t);
        m_rpos += sizeof(T);
        return result && m_rpos <= size();
    }

    template <typename T>
    bool read(size_t pos, T* t) const 
	{
        if (pos + sizeof(*t) > size())
            return false;
        *t = *((T const *)&m_storage[pos]);
        return true;
    }

    size_t size() const { return m_storage.size(); }

    bool empty() const  { return m_storage.empty(); }

    void resize(size_t new_size) 
	{
        m_storage.resize(new_size);
    }

    void reserve(size_t res_size) 
	{
        if (res_size > size()) 
		{
            m_storage.reserve(res_size);
        }
    }

    template<class T>
    bool append(const T* src, size_t cnt) 
	{
        return append((const uint8_t*)src, cnt * sizeof(T));
    }

    bool append(const uint8_t* src, size_t cnt) 
	{
        if (!cnt) 
		{
            return false;
        }
        MMO_ASSERT(size() < 1e7);
        if (m_storage.size() < m_wpos + cnt) 
		{
            m_storage.resize(m_wpos + cnt);
        }
        memcpy(&m_storage[m_wpos], src, cnt);
        m_wpos += cnt;
        return true;
    }

    template <typename T> bool append(T value) 
	{
        return append((uint8_t *)&value, sizeof(value));
    }

    bool put(size_t pos, const uint8_t* src, size_t cnt) 
	{
        if (pos + cnt > size()) 
		{
            return false;
        }
        memcpy(&m_storage[pos], src, cnt);
        return true;
    }
};
